// Package rpc rpc这个包充当一个api层去通过rpc调用微服务的一个中转站中
// 作用是建立一些rpc调用的客户端去分发参数
// 但是本质上还是属于api层
package rpc

import (
	"context"
	etcd "github.com/kitex-contrib/registry-etcd"
	"time"

	"github.com/cloudwego/kitex-examples/bizdemo/easy_note/kitex_gen/notedemo"
	"github.com/cloudwego/kitex-examples/bizdemo/easy_note/kitex_gen/notedemo/noteservice"
	"github.com/cloudwego/kitex-examples/bizdemo/easy_note/pkg/constants"
	"github.com/cloudwego/kitex-examples/bizdemo/easy_note/pkg/errno"
	"github.com/cloudwego/kitex-examples/bizdemo/easy_note/pkg/middleware"
	"github.com/cloudwego/kitex/client"
	"github.com/cloudwego/kitex/pkg/retry"
	trace "github.com/kitex-contrib/tracer-opentracing"
)

// notedemo这个微服务的客户端对象
// （注意包结构，就能看懂）
var noteClient noteservice.Client

// 这一块是初始化note的rpc客户端
func initNoteRpc() {
	r, err := etcd.NewEtcdResolver([]string{constants.EtcdAddress})
	if err != nil {
		panic(err)
	}

	c, err := noteservice.NewClient(
		constants.NoteServiceName,
		client.WithMiddleware(middleware.CommonMiddleware),
		client.WithInstanceMW(middleware.ClientMiddleware),
		client.WithMuxConnection(1),                       // mux
		client.WithRPCTimeout(3*time.Second),              // rpc timeout
		client.WithConnectTimeout(50*time.Millisecond),    // conn timeout
		client.WithFailureRetry(retry.NewFailurePolicy()), // retry
		client.WithSuite(trace.NewDefaultClientSuite()),   // tracer
		client.WithResolver(r),                            // resolver
	)
	if err != nil {
		panic(err)
	}
	noteClient = c
}

// CreateNote create note info
// CreateNote这个创建笔记的一个调用接口
// 正式充当rpc客户端调用微服务！！！
// 千万注意，返回值是error！！！
func CreateNote(ctx context.Context, req *notedemo.CreateNoteRequest) error {
	//noteClient是这个微服务的客户端，在执行initNoteRpc()方法时就创建好了
	//直接用客户端去发送rpc请求，请求的内容就是CreateNoteRequest类型的req
	//这个rpc返回两个参数，一个是响应结果，一个是错误
	//CreateNote这个方法是在idl中定义好的
	resp, err := noteClient.CreateNote(ctx, req)

	//错误处理，直接返回异常就行了
	if err != nil {
		return err
	}

	//如果没有异常
	//进行响应参数认证
	if resp.BaseResp.StatusCode != 0 {
		return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
	}
	//由于创建note接口不会返回具体响应体
	//这边直接返回空即可
	return nil
}

// QueryNotes query list of note info
// 查询笔记的接口！
// 正式充当rpc客户端调用微服务！！！
// 千万注意，返回值是一个Note列表、记录条数、错误
func QueryNotes(ctx context.Context, req *notedemo.QueryNoteRequest) ([]*notedemo.Note, int64, error) {
	//首先还是通过客户端去发送rpc请求
	//得到响应内容和err
	resp, err := noteClient.QueryNote(ctx, req)
	//错误处理，微服务执行过程中有错误
	if err != nil {
		return nil, 0, err
	}
	//如果微服务响应体有错误
	if resp.BaseResp.StatusCode != 0 {
		return nil, 0, errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
	}
	//响应体中都有，直接拿
	//但是最好封装成api层想要的样子
	return resp.Notes, resp.Total, nil
}

// UpdateNote update note info
// 更新笔记的接口！
// 正式充当rpc客户端调用微服务！！！
// 千万注意，返回值是一个error
func UpdateNote(ctx context.Context, req *notedemo.UpdateNoteRequest) error {
	//进行rpc远程调用
	resp, err := noteClient.UpdateNote(ctx, req)
	//错误处理
	if err != nil {
		return err
	}
	//错误处理
	if resp.BaseResp.StatusCode != 0 {
		return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
	}
	return nil
}

// DeleteNote delete note info
// 删除笔记的接口！
// 正式充当rpc客户端调用微服务！！！
// 千万注意，返回值是一个error
func DeleteNote(ctx context.Context, req *notedemo.DeleteNoteRequest) error {
	//api调用
	resp, err := noteClient.DeleteNote(ctx, req)
	//错误处理
	if err != nil {
		return err
	}
	if resp.BaseResp.StatusCode != 0 {
		return errno.NewErrNo(resp.BaseResp.StatusCode, resp.BaseResp.StatusMessage)
	}
	return nil
}
